package pl.edu.agh.uddiProxy.types;

import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.MapKey;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import org.hibernate.annotations.AccessType;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.providers.encoding.PasswordEncoder;
import org.springframework.security.userdetails.UserDetails;

import dk.itst.uddi.client.types.core.OperationalInfo;

import pl.edu.agh.uddiProxy.dao.DAOHelper;

@Table(name = "users",
	    uniqueConstraints = {@UniqueConstraint(columnNames={"username"})}
)

@AccessType("field")
@javax.persistence.Entity
public class User extends Entity implements UserDetails, Serializable {
	private static final long serialVersionUID = 8867232229188022522L;
	
	@Column(name = "username", nullable = false)
	private String username;
	@Column(name = "firstName", nullable = false)
	private String firstName;
	@Column(name = "lastName", nullable = false)
	private String lastName;
	@Column(name = "password", nullable = false)
	private String password;
	@Column(name = "email", nullable = false)
	private String email;
	@OneToMany(targetEntity = ServiceDynamicParameters.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @MapKey(name="username")
    @JoinTable(name = "user_service", joinColumns = @JoinColumn(name = "user_id"))
	private List<ServiceDynamicParameters> serviceList = new LinkedList<ServiceDynamicParameters>();
	@ManyToMany(targetEntity = Authority.class)
	@Cascade(value=org.hibernate.annotations.CascadeType.ALL)
	@LazyCollection(LazyCollectionOption.FALSE)
    @MapKey(name="id")
    @JoinTable(name = "user_authority", joinColumns = @JoinColumn(name = "user_id"))
	private Set<Authority> authoritySet = new HashSet<Authority>();
	
	public User() {
	}
	
	public User(String username, String firstName, String lastName,
			String password, String email) {
		super();
		
		PasswordEncoder encoder = DAOHelper.getPasswordEncoder();
		this.username = username;
		this.firstName = firstName;
		this.lastName = lastName;
		this.password = encoder.encodePassword(password, null);
		this.email = email;
	}

	public User(String username, String firstName, String lastName,
			String password, String email, Set<Authority> authoritySet) {
		this(username, firstName, lastName, password, email);
		this.authoritySet.addAll(authoritySet);
	}
	
	public String getUsername() {
		return username;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		PasswordEncoder encoder = DAOHelper.getPasswordEncoder();
		this.password = encoder.encodePassword(password, null);;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public List<ServiceDynamicParameters> getServiceList() {
		return serviceList;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((username == null) ? 0 : username.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (username == null) {
			if (other.username != null)
				return false;
		} else if (!username.equals(other.username))
			return false;
		return true;
	}

	public GrantedAuthority[] getAuthorities() {
		GrantedAuthority[] authorities = new GrantedAuthority[authoritySet.size()];
		return authoritySet.toArray(authorities);
	}

	public boolean isAccountNonExpired() {
		return true;
	}

	public boolean isAccountNonLocked() {
		return true;
	}

	public boolean isCredentialsNonExpired() {
		return true;
	}

	public boolean isEnabled() {
		return true;
	}
	
	public boolean isAdministrator() {
		return authoritySet.contains(Authority.getAuthority(Authority.ADMIN));
	}

	public boolean isUser() {
		return authoritySet.contains(Authority.getAuthority(Authority.USER));
	}
	
	public boolean containsAuthority(Authority a) {
		return authoritySet.contains(a);
	}
	
	public void addAuthority(Authority authority) {
		authoritySet.add(authority);
	}
	
	public boolean isOwner(String tModelKey) {
		OperationalInfo operationalInfo = DAOHelper.getUDDIClient().getInquiryClient().getOperationalInfo(tModelKey);
		return operationalInfo != null && operationalInfo.getAuthorizedName() != null && operationalInfo.getAuthorizedName().equals(username);
	}
}
